package edu.unlv.cs.ladders.web;

import java.util.ArrayList;
import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.roo.addon.web.mvc.controller.RooWebScaffold;

import edu.unlv.cs.ladders.entities.Participant;
import edu.unlv.cs.ladders.entities.Team;
import edu.unlv.cs.ladders.entities.Tournament;
import edu.unlv.cs.ladders.notification.NotificationService;
import edu.unlv.cs.ladders.services.PermissionService;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.stereotype.Controller;

@RooWebScaffold(path = "team", automaticallyMaintainView = false, formBackingObject = Team.class)
@RequestMapping("/team/**")
@Controller
public class TeamController {
	/**
	 * This might be better as a POST, but I'm doing this in haste.
	 * @param id
	 * @param modelMap
	 * @return
	 */
	@Transactional
	@PreAuthorize("hasRole('ROLE_PARTICIPANT')")
    @RequestMapping(value = "/team/{id}/join", method = RequestMethod.GET)
    public String joinTeam(@PathVariable("id") Long id, ModelMap modelMap) {
		Team team = Team.findTeam(id);
		if(team==null){
			throw new IllegalArgumentException("Team does not exist.");
		}
		Participant currentParticipant = Participant.getCurrentUser();
		team.addMember(currentParticipant);
		team.flush();
		team = Team.findTeam(team.getId());
		
		currentParticipant = Participant.findParticipant(currentParticipant.getId());
		currentParticipant.addTeam(team);
		currentParticipant.flush();
		getPermissionService().grantPermission(team,currentParticipant, BasePermission.WRITE);
		this.getNotificationService().notifyTeamMembersOfNewMember(team);
        return "redirect:/team/" + team.getId();
    }

	@PreAuthorize("hasRole('ROLE_PARTICIPANT')")
    @RequestMapping(value = "/team", method = RequestMethod.POST)
    public String create(@Valid Team team, BindingResult result, ModelMap modelMap) {
        if (team == null) throw new IllegalArgumentException("A team is required");
        if (result.hasErrors()) {
            modelMap.addAttribute("team", new Team());
            modelMap.addAttribute("tournaments", Tournament.findTournamentsByClosed(false).getResultList());
            return "team/create";
        }
        Participant currentUser = Participant.getCurrentUser();
        team.setCaptain(currentUser);
        //The initial position is the order they are inserted.
        team.setRank(team.getTournament().getTeams().size());
        team.persist();
        team.flush();
        
        team = Team.findTeam(team.getId());
        team.addMember(currentUser);
        
        currentUser = Participant.findParticipant(currentUser.getId());
        currentUser.addTeam(team);
        Tournament tournament = team.getTournament();
        tournament.addTeam(team);
        
        this.getPermissionService().setDefaultPermissions(team);
        return "redirect:/team/" + team.getId();
    }

	@PreAuthorize("hasRole('ROLE_PARTICIPANT')")
    @RequestMapping(value = "/team/form", method = RequestMethod.GET)
    public String createForm(ModelMap modelMap) {
        modelMap.addAttribute("team", new Team());
        modelMap.addAttribute("tournaments", findTournamentsCurrentUserCanJoin());
        return "team/create";
    }
	
	@SuppressWarnings("unchecked")
	private List<Tournament> findTournamentsCurrentUserCanJoin(){
		List<Tournament> original = Tournament.findTournamentsByClosed(false).getResultList();
		List<Tournament> tournaments = new ArrayList<Tournament>(original);
		for(Tournament tournament : original){
			Team team = tournament.findTeamWithMember(Participant.getCurrentUser());
			if(team!=null){
				tournaments.remove(tournament);
			}
		}
		return tournaments;
	}
    
    @RequestMapping(value = "/team/{id}", method = RequestMethod.GET)
    public String show(@PathVariable("id") Long id, ModelMap modelMap) {
        if (id == null) throw new IllegalArgumentException("An Identifier is required");
        Team team = Team.findTeam(id);
        Participant currentUser = Participant.getCurrentUser();
        modelMap.addAttribute("canJoin", team.canJoin(currentUser));
        modelMap.addAttribute("canChallenge",team.canChallenge(currentUser));
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        modelMap.addAttribute("team", team);
        return "team/show";
    }
    
    @RequestMapping(value = "/team", method = RequestMethod.GET)
    public String list(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, ModelMap modelMap) {
        if (page != null || size != null) {
            int sizeNo = size == null ? 10 : size.intValue();
            modelMap.addAttribute("teams", Team.findTeamEntries(page == null ? 0 : (page.intValue() - 1) * sizeNo, sizeNo));
            float nrOfPages = (float) Team.countTeams() / sizeNo;
            modelMap.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));
        } else {
            modelMap.addAttribute("teams", Team.findAllTeams());
        }
        return "team/list";
    }
    @PreAuthorize("hasPermission(#team,'write') or hasRole('ROLE_COORDINATOR')")
    @RequestMapping(method = RequestMethod.PUT)
    public String update(@Valid Team team, BindingResult result, ModelMap modelMap) {
        if (team == null) throw new IllegalArgumentException("A team is required");
        if (result.hasErrors()) {
            modelMap.addAttribute("team", team);
            modelMap.addAttribute("participants", team.getMembers());
            return "team/update";
        }
        boolean paid = team.getHasPaid();
        long id = team.getId();
        String name = team.getName();
        int rank = team.getRank();

        team = Team.findTeam(id);
        team.setHasPaid(paid);
        team.setName(name);
        team.setRank(rank);

        team.merge();
        return "redirect:/team/" + team.getId();
    }

    @PreAuthorize("hasPermission(#id,'edu.unlv.cs.ladders.entities.Team','write') or hasRole('ROLE_COORDINATOR')")
    @RequestMapping(value = "/team/{id}/form", method = RequestMethod.GET)
    public String updateForm(@PathVariable("id") Long id, ModelMap modelMap) {
        if (id == null) throw new IllegalArgumentException("An Identifier is required");
        Team team = Team.findTeam(id);
        modelMap.addAttribute("team", team);
        modelMap.addAttribute("participants", team.getMembers());
        return "team/update";
    }
    
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/team/{id}", method = RequestMethod.DELETE)
    public String delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size) {
        if (id == null) throw new IllegalArgumentException("An Identifier is required");
        Team.findTeam(id).remove();
        return "redirect:/team?page=" + ((page == null) ? "1" : page.toString()) + "&size=" + ((size == null) ? "10" : size.toString());
    }
    
    @RequestMapping(value = "find/ByTournament/form", method = RequestMethod.GET)
    public String findTeamsByTournamentForm(ModelMap modelMap) {
        modelMap.addAttribute("tournaments", Tournament.findAllTournaments());
        return "team/findTeamsByTournament";
    }
    
    @RequestMapping(value = "find/ByTournament", method = RequestMethod.GET)
    public String findTeamsByTournament(@RequestParam("tournament") Tournament tournament, ModelMap modelMap) {
        if (tournament == null) throw new IllegalArgumentException("A Tournament is required.");
        modelMap.addAttribute("teams", Team.findTeamsByTournament(tournament).getResultList());
        return "team/list";
    }
	private PermissionService permissionService;
	@Autowired
	public void setPermissionService(PermissionService permissionService) {
		this.permissionService = permissionService;
	}


	public PermissionService getPermissionService() {
		return permissionService;
	}

	private NotificationService notificationService;

	@Autowired
	public void setNotificationService(NotificationService notificationService) {
		this.notificationService = notificationService;
	}

	public NotificationService getNotificationService() {
		return notificationService;
	}
}
